
KING OF TIMEで打刻をしたらSlackで自動的にリアクションをするChrome拡張を作ってみた
こんにちは、CX事業本部の若槻です。
今回は、KING OF TIMEで出勤/退勤ボタンをクリック(打刻)したらSlackでメッセージにスタンプを自動で押す(リアクションする)Chrome拡張を作ってみたのでご紹介します。
背景
次の記事でも紹介されている通り、弊社では勤怠管理システムとしてKING OF TIME(KoT)を導入しています。
そのため日々の業務開始時および終了時に次のようなレコーダー画面で[出勤]および[退勤]ボタンをクリック(打刻)して勤怠を記録しています。
加えて、私が所属しているチームでは、Slackに毎日投稿される次のようなメッセージにリモートワーク開始時および終了時にりも開
およびりも終
スタンプで報告をするルールとなっています。(誰がいつ何のスタンプを押したかはスレッドに自動で追加される)
このルールによりメンバーのうち誰がいつリモートワークをしているのかチーム内で把握できるので便利なのですが、現在の状況下だと当分のあいだは原則的にリモートワークによる勤務であるためKoTとSlackの両方での出退勤時のルーチンが手間というのがありました。
これらを両方まとめてドーンと出来る方法がないか調べてみると、先人がAWS IoT Buttonを使ってKoTでの打刻とSlackでの報告をLambda上で実装していました。
しかし、LambdaにSelenium+Headlessブラウザによる処理を乗せるのは実装が重い、IoT Button持ってない、処理失敗に気づきにくい…等の理由により、この方法は断念しました。
そこで更に良い方法がないか調べてみたところ、**KoTでの打刻時にSlack APIを叩くChrome拡張を作るのが良さそう!**となり今回のChrome拡張の作成に至りました。
作ったもの
下記の2ファイルから成るGoogle Chrome拡張です。
// Slack AppのOAuth Access Tokenを指定
const slack_app_token = 'xoxp-0123456789-012345678901-012345678901-012345xxxxxx678901xxxxxx012345xxxxxx678901xxxxxx'
// Reaction対象のメッセージを検索するQueryを定義
search_word = 'Reminder: :rimokai: :rimoshu: はこのスレで!'
channel = '<チャネル名>'
from = 'slackbot'
encoded_query = encodeURI(`${search_word} in:${channel} from:${from}`)
// Reactionでスタンプする絵文字を定義
emoji_in = 'rimokai'
emoji_out = 'rimoshu'
// Reaction対象のメッセージのchannelのIDを定義
channel_id = '<チャネルID>'
// 最新のReminderメッセージにrimokai/rimoshuをReactionする
function reaction_to_reminder(emoji_name){
// Slack API(search.messages)のURIを定義(Queryにヒットするtimestampが最新のメッセージを1つ取得する)
var search_uri = `https://slack.com/api/search.messages?\
token=${slack_app_token}&\
query=${encoded_query}&\
sort=timestamp&\
sort_dir=desc&\
count=1`;
// Reaction対象のメッセージのtsをSlackから取得
fetch(search_uri)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
var json = JSON.parse(JSON.stringify(myJson))
var ts = json.messages.matches```0.ts;
// Slack API(reactions.add)のURIを定義
var reaction_uri = `https://slack.com/api/reactions.add?\
token=${slack_app_token}&\
channel=${channel_id}&\
name=${emoji_name}&\
timestamp=${ts}`;
// Reactionの実行
fetch(reaction_uri);
window.alert(`メッセージ"${ts}"に"${emoji_name}"がリアクションされました。`);
});
}
// KoTのタイムレコーダーページでイベントリスナーを設定
function set_event_listener(){
// 出勤ボタンに reaction_to_reminder('rimokai') を設定
var syukkin_elem = document.getElementsByClassName('record-btn-inner record-clock-in');
syukkin_elem```0.addEventListener('click', function(){reaction_to_reminder(emoji_in)}, false);
// 退勤ボタンに reaction_to_reminder('rimoshu') を設定
var taikin_elem = document.getElementsByClassName('record-btn-inner record-clock-out');
taikin_elem```0.addEventListener('click', function(){reaction_to_reminder(emoji_out)}, false);
window.alert(`打刻すると${channel}チャネルのReminderメッセージに"${emoji_in}"/"${emoji_out}"がリアクションされます。`);
};
// ボタンパーツの読み込みを1秒待つ
setTimeout("set_event_listener()", 1000);
{
"name": "slackot",
"short_name": "slackot",
"version": "1.0",
"manifest_version": 2,
"content_scripts": [
{
"matches": [ "https://s2.kingtime.jp/independent/recorder/personal/" ],
"js": [ "script.js" ]
}
]
}
ファイルの内容の説明
script.js
- Function
reaction_to_reminder(emoji_name)
により、リアクション先のメッセージの検索(Queryに一致、Timestampが最新)と、スタンプによるリアクションを行っている。 - Function
set_event_listener()
により、KoTのレコーダー画面上の出勤ボタンと退勤ボタンにクリックでreaction_to_reminder(emoji_name)
が発火するリスナーを設定している。 setTimeout("set_event_listener()", 1000)
により、出勤/退勤ボタンがDOMに読み込まれてからリスナーを設定するようにしている。
manifest.json
- KoTのレコーダー画面(
https://s2.kingtime.jp/independent/recorder/personal/
)でのみChrome拡張が有効になるようにしている。
使い方
設定
- 次の記事を参考に、
search.messages
とreactions.add
のSlack APIを使用可能なAppをSlackワークスペース上に作成します。
- Slack APIでメッセージの検索をしてみた(search.messages) | Developers.IO
- Slack APIでメッセージにリアクション(スタンプの付与)をしてみた(reactions.add) | Developers.IO
- 端末ローカルで任意の名前のディレクトリを作成し、前述の
script.js
とmanifest.json
の2ファイルを配置します。 script.js
を以下の要領で編集して変数を指定します。
- 2行目
slack_app_token
:手順1で作成したAppのOAuth Access Tokenを指定 - 5行目
search_word
:リアクションするメッセージを検索するワードを指定 - 6行目
channel
:リアクションするメッセージが投稿されているチャネル名を指定 - 7行目
from
:リアクションするメッセージを投稿したユーザー名を指定 - 11行目
emoji_in
:出勤時にリアクションするスタンプ名を指定 - 12行目
emoji_out
:退勤時にリアクションするスタンプ名を指定 - 15行目
channel_id
:リアクションするメッセージが投稿されているチャネルIDを指定
- Google Chromeで
chrome://extensions/
にアクセスし、デベロッパーモードを有効にし、[パッケージ化されていない拡張機能を読み込む]をクリック。
- 作成したファイルを選んで[選択]。
- 拡張機能として以下のように追加されたら設定は完了です。
使ってみる
Slackにbotで投稿されている次のメッセージが本日のリモートワーク開始/終了時にリアクションによる報告が必要なメッセージとなります。
KoTのレコーダー画面(https://s2.kingtime.jp/independent/recorder/personal/
)を開くと、次のようにボタンにリスナーを設定した旨のダイアログが出ます。```OKをクリックします。
退勤ボタンをクリックします。
メッセージにリアクションした旨のダイアログが出ます。```OKをクリックします。
Slack側でメッセージを見るとユーザー自身により指定のスタンプがリアクションされていることが確認できます。
おわりに
KING OF TIMEで出勤/退勤ボタンをクリック(打刻)したらSlackでメッセージにスタンプを自動で押す(リアクションする)Chrome拡張を作ってみました。
今回初めてChrome拡張を作りましたが案外かんたんなことが分かったので今後も色々作ってみたいです。
参考
- Slack API search.messages not supporting search in specific channel | Stack Overflow
- Google Chrome Extensionでコンテンツ側のクリックイベントを拾いたい | teratail
- JavaScriptのaddEventListener()の基本的な使い方 | UX MILK
- 今さら聞けないChromeエクステンションの作り方 | はらへり日記
- DOM の取得及び操作 | Qiita
- JavaScriptのイベント処理について | teratail
- Javascript error - document.getElementsById is not a function | Stack Overflow
- Javascriptのrequireを使う方法 | teratail
- 【JavaScript入門】JSONの作成とparse() / stringify()の使い方! | Samurai Blog
- 「JSON.stringify()」の使い方
- 「JSON.parse()」の使い方
- Fetch を使う | MDN web docs
- JavaScriptで文字列を複数行に分けて記述する方法 | プロカツ!
- JavaScript (ES2015) 文字列中に変数展開できるテンプレート構文のメモ | かもメモ
- 一定時間後に処理を行う(setTimeout) | Let'sプログラミング
- 【JavaScript入門】addEventListener()によるイベント処理の使い方! | Samurai Blog
- DOMContentLoadedイベントとloadイベントの違い[タイミング] | 思考の葉
- window.alert | MDN web docs
- Element: mouseover event | MDN web docs
- Node.js:JSONデータをPOSTする | Qiita
- Node.js で HTTP/HTTPS リクエスト を行う方法 | galife
- Node.jsでHTTP GETしてJSONパースするメモ | Qiita
- 【Node.js入門】https.get / requestによるJSONの取得・パース方法まとめ! | Samurai Blog
- addEventListenerでリスナー関数に引数を渡す | JavaScriptマスター
- encodeURI() | MDN web docs
以上